package scaladuct

import javax.validation.{ValidationException, ConstraintViolation, Validation, ValidatorFactory}
import java.lang.Class
import java.lang.reflect.Type

/**
 * <p>
 * Created by IntelliJ IDEA.
 * User: zslajchrt
 * Date: Jun 28, 2010
 * Time: 8:33:27 PM
 */
@serializable @SerialVersionUID(1L)
trait Starter[X] {
  def newInstance(): X

  def destroy(instance: X): Unit
}

@SerialVersionUID(1L)
class FunctionalStarter[X](creator: => X, destroyer: (X) => Unit = null) extends Starter[X] {
  def newInstance() = creator

  def destroy(instance: X) = if (destroyer != null)
    destroyer(instance)
  else
    null
}

@SerialVersionUID(1L)
class BasicStarter[X](val x: X) extends Starter[X] {
  def destroy(instance: X) = null

  def newInstance() = x
}

@SerialVersionUID(1L)
class BasicStarterWithType[X](x: X, productType: Type) extends BasicStarter[X](x) with HasProductType {
  def getProductType() = productType
}

@SerialVersionUID(1L)
class StarterDecorator[X](val decoratedStarter: Starter[X]) extends Starter[X] with ExtensibleDecorator {
  val decoratedForExtensible = decoratedStarter

  def destroy(instance: X) = decoratedStarter.destroy(instance)

  def newInstance() = decoratedStarter.newInstance
}

abstract class GenericStarter[X] extends Starter[X] {
  def newInstance(): X = {
    getClass.getMethods.find(m => m.getAnnotation(classOf[First]) != null) match {
      case None => throw new IllegalStateException("The first phase method not found")
      case Some(firstPhase) => {
        firstPhase.
                invoke(this, firstPhase.getParameterTypes.map(argClass => null)).
                asInstanceOf[X]
      }
    }
  }
}

object processInstance {
  def apply[X](starter: Starter[X])(action: X => Unit) {
    val instance: X = starter.newInstance
    try {
      action(instance)
    } finally {
      starter.destroy(instance)
    }
  }
}

